package org.jvm.rtda.heap.symref;

import org.jvm.rtda.heap.*;
import org.jvm.rtda.heap.classmember.Field;
import org.jvm.rtda.thread.Thread;

/**
 * 字段引用
 *
 * @author 王思翔
 * @date 2023/2/4
 */
public class FieldRef extends MemberRef {

    private Field field;


    public FieldRef(ConstantPool cp, String className, String name, String descriptor) {
        super(cp, className, name, descriptor);
    }

    /**
     * 解析被引用类的被引用的字段
     *
     * @return
     */
    public Field resolvedField(Thread thread) {
        Klass thisClass = this.cp.getKlass();
        Klass thatClass = resolvedClass(thread);
        //被引用字段
        Field field = lookupField(thatClass, this.name, this.descriptor);
        if (field == null) {
            throw new RuntimeException("无法找到被引用的字段");
        }
        this.field = field;
        //如果被引用字段不允许本类访问，抛异常
        if (!field.isAccessibleTo(thisClass)) {
            throw new RuntimeException("无被引用的字段访问权限");
        }
        return field;
    }

    /**
     * 从被引用类中寻找被引用的字段
     *
     * @param thatClass  被引用类
     * @param name       被引用字段名
     * @param descriptor 被引用字段描述
     * @return
     */
    private Field lookupField(Klass thatClass, String name, String descriptor) {
        if (thatClass == null) {
            return null;
        }
        //先从被引用类中直接寻找
        for (Field field : thatClass.getFields()) {
            if (field.getName().equals(name) && field.getDescriptor().equals(descriptor)) {
                return field;
            }
        }
        //如果找不到则从被引用类实现的接口中寻找
        for (Klass i : thatClass.getInterfaces()) {
            Field field = lookupField(i, name, descriptor);
            if (field != null) {
                return field;
            }
        }
        //如果找不到则从父类中寻找
        return lookupField(thatClass.getSuperClass(), name, descriptor);
    }
}
